import { _decorator, Component, error, instantiate, Node, Prefab } from 'cc';
const { ccclass, property } = _decorator;

export type NodePoolCallback = (obj: Node) => void;

@ccclass('pool/NodePool')
export class NodePool extends Component {
    private _pool: Node[] = [];
    public onInstantiate: NodePoolCallback = null;
    public onPop: NodePoolCallback = null;
    public onPut: NodePoolCallback = null;

    @property(Prefab)
    private prefab: Prefab | Node;

    protected onLoad(): void {
        if (this.prefab == null) {
            if (this.node.children.length == 0) {
                error(`nodePool: ${this.node.name}'s prefab is null`);
            }

            this.prefab = this.node.children[0];
        }
    }

    public get(parent: Node = null) {
        let node: Node = this._pool.pop();
        if (node == null) {
            node = instantiate(this.prefab) as Node;
            if (this.onInstantiate) {
                this.onInstantiate(node);
            }
        }

        if (this.onPop) {
            this.onPop(node);
        }

        if (parent) {
            node.setParent(parent);
        } else {
            node.setParent(this.node);
        }

        node.active = true;
        return node;
    }

    public put(node: Node) {
        node.setParent(this.node);
        node.active = false;
        this._pool.push(node);
        if (this.onPut) {
            this.onPut(node);
        }
    }

    public clear() {
        this._pool.forEach((node: Node) => {
            if (node.isValid) {
                node.destroy();
            }
        });

        this._pool = [];
    }

    protected onDestroy(): void {
        this.clear();
    }
}